package neptune.manager.storage;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import neptune.manager.model.ApplicationProperties;


/**
 * 
 * @author Luigi Lorenzo Arpino [luigiarpino@yahoo.it]
 *
 */
public class XMLApplicationPropertiesStorage implements ApplicationPropertiesStorage
{
	
	private File xmlFile;

	/**
	 * @param xmlFile
	 */
	public XMLApplicationPropertiesStorage(File xmlFile) 
	{
		this.xmlFile = xmlFile;
	}

	@Override
	public ApplicationProperties getApplicationProperties() throws StorageReadException 
	{
		ApplicationProperties appProp=new ApplicationProperties();
		// Parsing file XML
		DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
		docFactory.setValidating(false); // La validazione e' intesa solo in
		// riferimento ai DTD

		// TODO inserire riferimento a XML SCHEMA
		// docFactory.setSchema(schema)

		try 
		{
			Document doc = docFactory.newDocumentBuilder().parse(xmlFile);
			Element configurationEl = doc.getDocumentElement();

			NodeList nodes = configurationEl.getElementsByTagName("vmTemplatesDir");
			Element element = (Element)nodes.item(0);
			String vmTemplatesDir = element.getAttribute("absolutePath");
			appProp.setVmTemplatesDir(vmTemplatesDir);
			
			nodes = configurationEl.getElementsByTagName("experimentsVMsDir");
			element = (Element)nodes.item(0);
			String experimentsVMsDir =  element.getAttribute("absolutePath");
			appProp.setExperimentsVMsDir(experimentsVMsDir);
			
			nodes = configurationEl.getElementsByTagName("debug");
			element = (Element)nodes.item(0);
			String stringDebug=element.getAttribute("active");
			if (stringDebug.equalsIgnoreCase("yes"))
			{
				appProp.setIsDebug(true);
			}
			else
			{
				appProp.setIsDebug(false);
			}
			
			nodes = configurationEl.getElementsByTagName("controlIpRanges");
			element = (Element)nodes.item(0);
			NodeList nodes2 = element.getElementsByTagName("ipRange");
			element = (Element) nodes2.item(0);
			String netmaskControlIpRange=element.getAttribute("netmask");
			appProp.setNetmaskControlIpRange(netmaskControlIpRange);
			String startIpControlIpRange=element.getAttribute("startIP");
			appProp.setStartIpControlIpRange(startIpControlIpRange);
			String endIpControlIpRange=element.getAttribute("endIP");
			appProp.setEndIpControlIpRange(endIpControlIpRange);
			String gatewayControlIpRange=element.getAttribute("gateway");
			appProp.setGatewayControlIpRange(gatewayControlIpRange);
			// Cluster Subnet
			nodes = configurationEl.getElementsByTagName("clusterSubnet");
			element = (Element)nodes.item(0);
			String addressClusterSubnet=element.getAttribute("address");
			appProp.setAddressClusterSubnet(addressClusterSubnet);
			String netmaskClusterSubnet = element.getAttribute("netmask");
			appProp.setNetmaskClusterSubnet(netmaskClusterSubnet);
			// Experiment Subnet
			nodes = configurationEl.getElementsByTagName("experimentsSubnet");
			element = (Element)nodes.item(0);
			String baseAddressExperimentSubnet=element.getAttribute("baseAddress");
			appProp.setBaseAddressExperimentSubnet(baseAddressExperimentSubnet);
			String netmaskExperimentSubnet = element.getAttribute("netmask");
			appProp.setNetmaskExperimentSubnet(netmaskExperimentSubnet);
			// Netmask link subnet
			nodes = configurationEl.getElementsByTagName("linkSubnet");
			element = (Element)nodes.item(0);
			String netmaskLinkSubnet = element.getAttribute("netmask");
			appProp.setNetmaskLinkSubnet(netmaskLinkSubnet);
		} 
		catch (SAXException e) 
		{
			throw new StorageReadException(e);
		} 
		catch (IOException e) 
		{
			throw new StorageReadException(e);
		}
		catch (ParserConfigurationException e) 
		{
			throw new StorageReadException(e);
		}
		return appProp;
	}

	@Override
	public void setApplicationProperties(ApplicationProperties appProperties) throws StorageSaveException 
	{
		String xmlString = getXML(appProperties);
		try 
		{
			xmlFile.createNewFile();
			FileWriter writer = new FileWriter(xmlFile);
			writer.write(xmlString);
			writer.flush();
		} 
		catch (IOException e) 
		{
			throw new StorageSaveException(e);
		}
	}

	public String getXML(ApplicationProperties appProperties) throws StorageSaveException 
	{
		DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
		docFactory.setValidating(false);
		
		try {
			Document document = docFactory.newDocumentBuilder().newDocument();
			document.setXmlVersion("1.0");
		
			Element root = document.createElement("configuration");
			document.appendChild(root);
		
			Element nodeEl = document.createElement("clusterDescriptor");
			nodeEl.setAttribute("relativePath", "cluster.xml");
			root.appendChild(nodeEl);
			
			nodeEl = document.createElement("topologiesDir");
			nodeEl.setAttribute("relativePath", "topologies");
			root.appendChild(nodeEl);
			
			nodeEl = document.createElement("experimentsDir");
			nodeEl.setAttribute("relativePath", "experiments");
			root.appendChild(nodeEl);
			
			nodeEl = document.createElement("templatesDir");
			nodeEl.setAttribute("relativePath", "templates");
			root.appendChild(nodeEl);
			
			nodeEl = document.createElement("vmTemplatesDir");
			nodeEl.setAttribute("absolutePath", appProperties.getVmTemplatesDir());
			root.appendChild(nodeEl);
			
			nodeEl = document.createElement("experimentsVMsDir");
			nodeEl.setAttribute("absolutePath", appProperties.getExperimentsVMsDir());
			root.appendChild(nodeEl);
			
			nodeEl = document.createElement("debug");
			String value;
			if (appProperties.isDebug())
			{
				value="yes";
			}
			else
			{
				value="no";
			}
			nodeEl.setAttribute("active", value);
			root.appendChild(nodeEl);
			
			//controlIpRanges
			nodeEl = document.createElement("controlIpRanges");
			Element childEl = document.createElement("ipRange");
			childEl.setAttribute("netmask", appProperties.getNetmaskControlIpRange());
			childEl.setAttribute("startIP", appProperties.getStartIpControlIpRange());
			childEl.setAttribute("endIP", appProperties.getEndIpControlIpRange());
			childEl.setAttribute("gateway", appProperties.getGatewayControlIpRange());
			nodeEl.appendChild( childEl );
			root.appendChild(nodeEl);
			
			//clusterSubnet
			nodeEl = document.createElement("clusterSubnet");
			nodeEl.setAttribute("address", appProperties.getAddressClusterSubnet());
			nodeEl.setAttribute("netmask", appProperties.getNetmaskClusterSubnet());
			root.appendChild(nodeEl);
			
			//experimentsSubnet
			nodeEl = document.createElement("experimentsSubnet");
			nodeEl.setAttribute("baseAddress", appProperties.getBaseAddressExperimentSubnet());
			nodeEl.setAttribute("netmask", appProperties.getNetmaskExperimentSubnet());
			root.appendChild(nodeEl);
			
			//linkSubnet
			nodeEl = document.createElement("linkSubnet");
			nodeEl.setAttribute("netmask", appProperties.getNetmaskLinkSubnet());
			root.appendChild(nodeEl);
			
			// ///////////////
			// Output the XML
		
			// set up a transformer
			TransformerFactory transfac = TransformerFactory.newInstance();
			Transformer trans = transfac.newTransformer();
			trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
			trans.setOutputProperty(OutputKeys.INDENT, "yes");
			trans.setOutputProperty(OutputKeys.STANDALONE, "yes");
			trans.setOutputProperty(
					"{http://xml.apache.org/xslt}indent-amount", "2");
		
			// create string from xml tree
			StringWriter sw = new StringWriter();
			StreamResult result = new StreamResult(sw);
			DOMSource source = new DOMSource(document);
			trans.transform(source, result);
			return sw.toString();
		
		} catch (ParserConfigurationException e) {
			throw new StorageSaveException(e);
		} catch (TransformerException e) {
			throw new StorageSaveException(e);
		}
	}
	
	public static void main(String[] args) throws StorageSaveException
	{
		ApplicationProperties appProperties=new ApplicationProperties();
		appProperties.setVmTemplatesDir("setVmTemplatesDir");
		appProperties.setExperimentsVMsDir("ExperimentsVMsDir");
		appProperties.setIsDebug(true);
		appProperties.setNetmaskControlIpRange("NetmaskControlIpRange");
		appProperties.setStartIpControlIpRange("StartIpControlIpRange");
		appProperties.setEndIpControlIpRange("EndIpControlIpRange");
		appProperties.setAddressClusterSubnet("AddressClusterSubnet");
		appProperties.setNetmaskClusterSubnet("NetmaskClusterSubnet");
		appProperties.setBaseAddressExperimentSubnet("BaseAddressExperimentSubnet");
		appProperties.setNetmaskExperimentSubnet("NetmaskExperimentSubnet");
		appProperties.setNetmaskLinkSubnet("NetmaskLinkSubnet");
		XMLApplicationPropertiesStorage storage=new XMLApplicationPropertiesStorage(new File("/etc/emuPlugin/configuration.xml"));
		System.out.println( storage.getXML(appProperties) );
		
	}
}
